﻿namespace npantarhei.contrib.mef
{
	using System;
	using System.ComponentModel.Composition.Primitives;
	using System.Reflection;
	using npantarhei.runtime.contract;
	using npantarhei.runtime.messagetypes;
	using npantarhei.runtime.patterns;

	public class ExportedOperation : AOperation
	{
		private readonly Delegate _implementation;

		public ExportedOperation(Lazy<object, IOperationMetadata> export, string name)
			: base(name)
		{
			var instance = export.Value as ExportedDelegate;
			this._implementation = instance.CreateDelegate(export.Metadata.MethodType);
		}

		public ExportedOperation(Export export, string name)
			: base(name)
		{
			var instance = export.Value as ExportedDelegate;
			var type = export.Metadata["MethodType"] as Type;

			this._implementation = instance.CreateDelegate(type);
		}

		protected override void Process(IMessage input, Action<IMessage> continueWith, Action<FlowRuntimeException> unhandledException)
		{
			Console.WriteLine(input.Port.Fullname);

			try
			{
				var result = this._implementation.Method.Invoke(this._implementation.Target, new[] { input.Data });
				if (this._implementation.Method.ReturnType == typeof(void))
				{
					result = input.Data;
				}

				continueWith(new Message(this.Name, result, input.CorrelationId));
			}
			catch (TargetInvocationException ex)
			{
				unhandledException(new FlowRuntimeException(ex.InnerException, input));
			}
			catch (Exception ex)
			{
				unhandledException(new FlowRuntimeException(ex, input));
			}
		}
	}
}